/*
 * @(#)QualifiedName.java	1.0 2000/12/14
 *
 * Copyright 2000 Thomas Barnekow. All Rights Reserved.
 *
 * This software is the proprietary information of Thomas Barnekow.
 * Use is subject to license terms.
 */

package tb.util;

import java.io.*;
import java.util.*;

/**
 * A qualified name consisting of several <i>components</i> delimited by a <i>delimiter</i>.
 *
 * @author Thomas Barnekow
 * @version 1.0
 */
public class QualifiedName implements Comparable, Cloneable, Serializable {

  /**
   * The empty name: "" (empty string)
   */
	public static final String EMPTY_NAME = "";

  public static final QualifiedName EMPTY_QUALIFIED_NAME = new QualifiedName();

	/**
	 * The default delimiter: "."
	 */
	public static final String DEFAULT_DELIMITER = ".";

	/**
	 * The qualified name's components
	 */
	private String[] m_components;

	/**
	 * Delimiter, e.g., ".", "-", or "::"
	 */
	private String m_delimiter;

	/**
	 * Cache storing string representation
	 */
	private String m_string;

  /**
   * Default constructor yielding a <i>QualifiedName</i> with zero components,
   * i.e., the <i>EMPTY_NAME</i>.
   */
	public QualifiedName() {
		this(new String[0]);
	}

	/**
	 * Constructor parsing a <i>String</i> delimited by the <i>DEFAULT_DELIMITER</i>
	 */
  public QualifiedName(String qualifiedName) {
		this(components(qualifiedName, DEFAULT_DELIMITER), DEFAULT_DELIMITER);
  }

	/**
	 * Constructor parsing a <i>String</i> delimited by the given <i>delimiter</i>
	 */
	public QualifiedName(String qualifiedName, String delimiter) {
    this(components(qualifiedName, delimiter), delimiter);
	}

	/**
	 * Constructor creating a <i>QualifiedName</i> that <br>
	 * - consists of the given <i>components</i> and <br>
	 * - is delimited by the <i>DEFAULT_DELIMITER</i>
	 */
  public QualifiedName(String components[]) {
		this(components, DEFAULT_DELIMITER);
	}

	/**
	 * Constructor creating a <i>QualifiedName</i> that <br>
	 * - consists of the given <i>components</i> and <br>
	 * - is delimited by the given <i>delimiter</i>
	 */
	public QualifiedName(String components[], String delimiter) {
    if (components == null || delimiter == null || delimiter.length() == 0)
			throw new IllegalArgumentException();

		m_components = components;
		m_delimiter = delimiter;
	}

	/**
	 * Constructor creating a <i>QualifiedName</i> that <br>
	 * - consists of a subset of the given <i>components</i> and <br>
	 * - is delimited by the <i>DEFAULT_DELIMITER</i>
	 */
	public QualifiedName(String components[], int pos, int length) {
		this(components, pos, length, DEFAULT_DELIMITER);
	}

	/**
	 * Constructor creating a <i>QualifiedName</i> that <br>
	 * - consists of a subset of the given <i>components</i> and <br>
	 * - is delimited by the given <i>delimiter</i>
	 */
	public QualifiedName(String components[], int pos, int length, String delimiter) {
    if (components == null || delimiter == null || delimiter.length() == 0)
			throw new IllegalArgumentException();

		m_components = new String[length];
		m_delimiter = delimiter;
		System.arraycopy(components, pos, m_components, 0, length);
	}

	/**
	 * Copy constructor
	 */
	public QualifiedName(QualifiedName qn) {
		this(qn.m_components, 0, qn.m_components.length, qn.m_delimiter);
	}

	/**
	 * Selective copy constructor
	 */
	public QualifiedName(QualifiedName qn, int pos, int length) {
		this(qn.m_components, pos, length, qn.m_delimiter);
	}

	/**
	 * Concatenation constructor
	 */
	public QualifiedName(QualifiedName qn, String component) {
    if (qn == null || component == null)
			throw new IllegalArgumentException();

		int length = component.length() > 0 ? qn.m_components.length + 1 : qn.m_components.length;

		m_components = new String[length];
		m_delimiter = qn.m_delimiter;

    System.arraycopy(qn.m_components, 0, m_components, 0, qn.m_components.length);
    if (qn.m_components.length < length)
			m_components[qn.m_components.length] = component;
  }

	/**
	 * Concatenation constructor
	 */
	public QualifiedName(QualifiedName qn, QualifiedName rn) {
    if (qn == null || rn == null)
			throw new IllegalArgumentException();

		m_components = new String[qn.m_components.length + rn.m_components.length];
		m_delimiter = qn.m_delimiter;

		System.arraycopy(qn.m_components, 0, m_components, 0, qn.m_components.length);
		System.arraycopy(rn.m_components, 0, m_components, qn.m_components.length, rn.m_components.length);
	}

	/*
	 * Static factory methods
	 */

	/**
	 * Create a <i>QualifiedName</i> from a <i>String</i> delimited by the <i>DEFAULT_DELIMITER</i>
	 */
	public static QualifiedName parse(String qualifiedName) {
		return parse(qualifiedName, DEFAULT_DELIMITER);
	}

	/**
	 * Create a <i>QualifiedName</i> from a <i>String</i> delimited by the given <i>delimiter</i>
	 */
	public static QualifiedName parse(String qualifiedName, String delimiter) {
		return new QualifiedName(components(qualifiedName, delimiter), delimiter);
	}

	/**
	 * Copy the given <i>QualifiedName</i> retaining its delimiter
	 */
	public static QualifiedName copy(QualifiedName source) {
		return copy(source, source.m_delimiter);
	}

	/**
	 * Copy the given <i>QualifiedName</i> changing the delimiter the given one
	 */
	public static QualifiedName copy(QualifiedName source, String delimiter) {
		return new QualifiedName(source.m_components, delimiter);
	}

	/**
	 * Get the <i>qualifiedName</i>'s components, which are delimited by the <i>DEFAULT_DELIMITER</i>
	 */
	public static String[] components(String qualifiedName) {
		return components(qualifiedName, DEFAULT_DELIMITER);
	}

	/**
	 * Get the <i>qualifiedName</i>'s components, which are delimited by the given <i>delimiter</i>
	 */
	public static String[] components(String qualifiedName, String delimiter) {
    if (qualifiedName == null || delimiter == null || delimiter.length() == 0)
			throw new IllegalArgumentException();

		StringTokenizer st = new StringTokenizer(qualifiedName, delimiter);

    int count = st.countTokens();
    String components[] = new String[count];

    for (int i = 0 ; i < count ; i++)
      components[i] = st.nextToken();

		return components;
	}

	/*
	 * NamedObject methods
	 */

	public String getFirstNameComponent() {
    return getNameComponent(0);
  }

  public String getLastNameComponent() {
    return getNameComponent(m_components.length - 1);
  }

  public String getNameComponent(int index) {
    if (0 <= index && index < m_components.length)
      return m_components[index];
    else
			throw new IndexOutOfBoundsException("No such name component: " + index);
  }

	/**
	 * For example, for the qualified (table) name "scott.emp" the namespace name
	 * is "scott".
	 */
	public QualifiedName getNamespaceName() {
		if (m_components.length > 0)
			return new QualifiedName(this, 0, m_components.length - 1);
		else
			return null;
	}

	/**
	 * Returns the number of name components.
	 */
  public int nameComponents() {
    return m_components.length;
  }

	/**
	 * Returns the <i>String</i> representation of this <i>QualifiedName</i> using
	 * the given <i>delimiter</i> to delimit the name components.
	 */
	public String toString(String delimiter) {
		if (m_components.length == 0) {
			return EMPTY_NAME;
		}

		StringBuffer buffer = new StringBuffer(m_components.length * 10);

		buffer.append(m_components[0]);
		for (int i = 1 ; i < m_components.length ; i++) {
			buffer.append(delimiter).append(m_components[i]);
		}
		return buffer.toString();
  }

	public QualifiedName copy(String delimiter) {
		return copy(this, delimiter);
	}

	/*
	 * Object operations
	 */

	public String toString() {
		if (m_string == null) {
			m_string = toString(m_delimiter);
		}
		return m_string;
	}

	public int hashCode() {
		return toString().hashCode();
	}

	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof QualifiedName))
			return false;

		QualifiedName qn = (QualifiedName) obj;

		if (m_delimiter.equals(qn.m_delimiter))
			return toString().equals(qn.toString());
		else
			return toString().equals(qn.toString(m_delimiter));
	}

	/*
	 * Comparable operations
	 */

	public int compareTo(Object obj) {
		if (obj != null)
			return toString().compareTo(obj.toString());
		else
			throw new NullPointerException();
	}

  /*
   * String operations
   */

  public QualifiedName toLowerCase() {
    String lcc[] = new String[m_components.length];
    for (int i = 0 ; i < m_components.length ; i++) {
      lcc[i] = m_components[i].toLowerCase();
    }
    return new QualifiedName(lcc, m_delimiter);
  }

  public QualifiedName toUpperCase() {
    String ucc[] = new String[m_components.length];
    for (int i = 0 ; i < m_components.length ; i++) {
      ucc[i] = m_components[i].toUpperCase();
    }
    return new QualifiedName(ucc, m_delimiter);
  }
}